// ANSI C includes
#include <cstdlib>

// C++ includes
#include <iostream>
using namespace std;

// Qt includes
#include <qapplication.h>
#include <qregexp.h>
#include <qdir.h>

// MythTV plugin includes
#include <mythtv/mythcontext.h>
#include <mythtv/mythwidgets.h>
#include <mythtv/lcddevice.h>
#include <mythtv/mythmedia.h>
#include <mythtv/audiooutput.h>
#include <mythtv/mythdbcon.h>

// MythMusic includes
#include "constants.h"
#include "streaminput.h"
#include "decoder.h"
#include "playbackbox.h"
#include "mainvisual.h"
#include "search.h"
#include "ScanForAudio.h"
#include "metadata.h"

extern QValueVector<SelectionInfo>  SelectionItemList;
extern QValueVector<SelectionInfo>  PlaybackItemList;

extern QString m_AddAll;
extern QString m_MetaUnknown;
extern ScanForAudio* m_FileScanner;

void PlaybackBoxMusic::AudioPlayer_State( SelectionInfo& info, PLAYER_STATE state )
{
   printf( "Player state %d\n", state );
}

void PlaybackBoxMusic::AudioPlayer_Progress( int position, int length )
{
   printf( "Position %d, length %d\n", position, length );
}

void PlaybackBoxMusic::AudioPlayer_Error( QString err )
{
   printf( "AudioPlayer Error: %s\n", err.ascii() );
}

PlaybackBoxMusic::PlaybackBoxMusic
(
   MythMainWindow *parent,
   QString window_name,
   QString theme_filename,
   const char *name,
   AudioPlayer& player
) :
   MythThemedDialog(parent, window_name, theme_filename, name),
   m_AudioPlayer(player)
{
   //  A few internal variable defaults

   mainvisual = NULL;
   visual_mode_timer = NULL;
   lcd_update_timer = NULL;
   banner_timer = NULL;
   playlist_popup = NULL;
   ModifyingPlaylist = false;
   KeypressIdleTimer = new QTimer(this);
   connect( KeypressIdleTimer, SIGNAL(timeout()), this, SLOT(KeypressIdle()));

   isplaying = false;
   first_playlist_check = true;
   outputBufferSize = 256;
   currentTime = 0;
   maxTime = 0;
   setContext(0);
   visual_mode_timer = new QTimer(this);
   visualizer_status = 0;
   curMeta = NULL;

   banner_timer = new QTimer(this);
   connect(banner_timer, SIGNAL(timeout()), this, SLOT(bannerDisable()));

   menufilters = gContext->GetNumSetting("MusicMenuFilters", 0);

   // Set our pointers the playlists and the metadata containers

   TextTransform = new CharacterProcessor();

   // Get some user set options

   keyboard_accelerators = gContext->GetNumSetting("MythAudio.KeyboardAccelerators", 1);

   showrating = gContext->GetNumSetting("MusicShowRatings", 0);

   // Through the magic of themes, our "GUI" already exists we just need to
   // wire up it

   wireUpTheme();

   CurrentSearch = new SearchEvent();
   CurrentSearch->prepare
   (
      "SELECT filename, artist from audio_tracks "
      "group by artist order by artist;"
   );
   CurrentSearch->State = SEARCH_STATE_ARTIST;
   PerformSearch( CurrentSearch );
   CurrentSearch->prepare
   (
      "SELECT filename, artist from audio_tracks where artist_search "
      "regexp :EXPRESSION "
      "group by artist order by artist;"
   );
   CurrentSearch->bindValue( ":EXPRESSION", "[[:<:]]" );

   // Possibly (user-defined) control the volume

   if( !keyboard_accelerators )
   {
      if( !assignFirstFocus() )
      {
         cerr << "playbackbox.o: Could not find a button to assign focus "
         "to. What's in your theme?" << endl;
         exit(0);
      }
   }

   if( class LCD *lcd = LCD::Get() )
   {
      // Set please wait on the LCD
      QPtrList<LCDTextItem> textItems;
      textItems.setAutoDelete(true);

      textItems.append(new LCDTextItem(1, ALIGN_CENTERED, "Please Wait",
                                       "Generic"));
      lcd->switchToGeneric(&textItems);
   }

   // Warm up the visualizer

   mainvisual = new MainVisual(this);
   mainvisual->setGeometry(screenwidth + 10, screenheight + 10, 160, 160);
   mainvisual->show();

   visual_mode = gContext->GetSetting("MythAudio.VisualMode");
   visual_mode.simplifyWhiteSpace();
   visual_mode.replace(QRegExp("\\s"), ",");

   QString visual_delay = gContext->GetSetting("MythAudio.VisualModeDelay");
   bool delayOK;
   visual_mode_delay = visual_delay.toInt(&delayOK);
   if( !delayOK )
   {
      visual_mode_delay = 0;
   }
   if( visual_mode_delay > 0 )
   {
      visual_mode_timer->start(visual_mode_delay * 1000);
      connect(visual_mode_timer, SIGNAL(timeout()), this, SLOT(visEnable()));
   }
   visualizer_status = 1;

   // Temporary workaround for visualizer Bad X Requests
   //
   // start on Blank, and then set the "real" mode after
   // the playlist timer fires. Seems to work.
   //
   // Suspicion: in most modes, SDL is not happy if the
   // window doesn't fully exist yet  (????)

   mainvisual->setVisual("Blank");

   // Ready to go. Let's update the foreground just to be safe.

   updateForeground();

   if( class LCD *lcd = LCD::Get() )
   {
      lcd->switchToTime();
   }
}

PlaybackBoxMusic::~PlaybackBoxMusic(void)
{
   if( class LCD *lcd = LCD::Get() )
   {
      lcd->switchToTime();
   }
}

void PlaybackBoxMusic::keyPressEvent(QKeyEvent* e)
{
   QStringList actions;
   QString action;
   bool handled = false;

   KeypressIdleTimer->start(5*1000,true);
   resetTimer();

   gContext->GetMainWindow()->TranslateKeyPress( "Audio", e, actions );

   if( actions.size() > 0 )
   {
      action = actions[0];
      handled = true;

      if( action == "PLAY" )
      {
         play();
      }
      else if ( action == "PAUSE" )
      {
         if( m_AudioPlayer.IsPlaying() )
         {
            m_AudioPlayer.Suspend();
         }
         else
         {
            m_AudioPlayer.Resume();
         }
      }
      else if ( action == "STOP" )
      {
         m_AudioPlayer.Stop();
      }
      else if ( action == "REWIND" )
      {
      }
      else if ( action == "FORWARD" )
      {
      }
      else if ( action == "REPLAY" )
      {
         m_AudioPlayer.Previous();
         m_AudioPlayer.Play();
      }
      else if ( action == "SKIP" )
      {
         m_AudioPlayer.Next();
         m_AudioPlayer.Play();
      }
      else if ( action == "INFO" )
      {
      }
      else if ( action == "ESCAPE" )
      {
         // Exit the app
         if( ModifyingPlaylist )
         {
            PlayListUI->SetActive( false );
            SelectionListUI->SetActive( true );
         }
         else
         {
            if( !BackOutSelection() )
            {
               // Done undoing, exit app
               handled = false;
            }
         }
      }
      else if ( action == "MENU" )
      {
         showMenu();
      }
      else
      {
         if( SelectionListUI->IsActive() )
         {
            handled = ProcessSearchEvent( action );
         }
         else
         {
            handled = ProcessPlaylistEvent( action );
         }
      }

      if( !handled )
      {
         MythThemedDialog::keyPressEvent(e);
      }
   }
}

bool PlaybackBoxMusic::ProcessSearchEvent( QString action )
{
   bool handled = true;
   bool search = true;
   QVariant tmp = CurrentSearch->boundValue(":EXPRESSION");
   QString exp = "";

   if( tmp.isValid() )
   {
      exp = tmp.asString();
   }

   if( action == "1" )
   {
      exp = exp + "[1]";
   }
   else if( action == "2" )
   {
      exp = exp + "[2abc]";
   }
   else if( action == "3" )
   {
      exp = exp + "[3def]";
   }
   else if( action == "4" )
   {
      exp = exp + "[4ghi]";
   }
   else if( action == "5" )
   {
      exp = exp + "[5jkl]";
   }
   else if( action == "6" )
   {
      exp = exp + "[6mno]";
   }
   else if( action == "7" )
   {
      exp = exp + "[7pqrs]";
   }
   else if( action == "8" )
   {
      exp = exp + "[8tuv]";
   }
   else if( action == "9" )
   {
      exp = exp + "[9wxyz]";
   }
   else if( action == "0" )
   {
      exp = exp + "[0 ]";
   }
   else if( action == "#" )
   {
   }
   else if( action == "*" )
   {
      // Any character
      exp = exp + ".";
   }
   else if( action == "UP" )
   {
      SelectionListUI->LineUp();
      search = false;
   }
   else if( action == "DOWN" )
   {
      SelectionListUI->LineDown();
      search = false;
   }
   else if( action == "LEFT" )
   {
      if( ModifyingPlaylist )
      {
         PlayListUI->SetActive( false );
         SelectionListUI->SetActive( true );
         search = false;
      }
      else
      {
         if( BackOutSelection() )
         {
            search = false;
         }
      }
   }
   else if( action == "RIGHT" )
   {
      if( ModifyingPlaylist )
      {
      }
      else
      {
         SelectionListUI->SetActive( false );
         PlayListUI->SetActive( true );
      }
      search = false;
   }
   else if( action == "PAGEUP" )
   {
      SelectionListUI->PageUp();
      search = false;
   }
   else if( action == "PAGEDOWN" )
   {
      SelectionListUI->PageDown();
      search = false;
   }
   else if( action == "SELECT" )
   {
      PerformSelect();
      search = false;
   }
   else
   {
      handled = false;
      search = false;
   }

   if( search )
   {
      SearchEvent* tmp = new SearchEvent( *CurrentSearch );
      SearchStack.push( tmp );
      CurrentSearch->bindValue( ":EXPRESSION", exp );
      PerformSearch( CurrentSearch );
   }

   return handled;
}

bool PlaybackBoxMusic::ProcessPlaylistEvent( QString action )
{
   bool handled = false;

   if( action == "LEFT" )
   {
      SelectionListUI->SetActive( true );
      PlayListUI->SetActive( false );
   }
   else if( action == "RIGHT" )
   {
   }
   else if( action == "INFO" )
   {
   }
   else if( action == "MENU" )
   {
   }
   else if( action == "UP" )
   {
      PlayListUI->LineUp();
   }
   else if( action == "DOWN" )
   {
      PlayListUI->LineDown();
   }
   else if( action == "PAGEUP" )
   {
      PlayListUI->PageUp();
   }
   else if( action == "PAGEDOWN" )
   {
      PlayListUI->PageDown();
   }
   else if( action == "SELECT" )
   {
      SelectionInfo info = PlayListUI->GetCurrent();
      //PlayFile( info.Path );
      m_AudioPlayer.Play();
      //nplay();
   }

   return handled;
}

void PlaybackBoxMusic::PerformSelect()
{
   QString tmp;
   int i;

   SelectionInfo info = SelectionListUI->GetCurrent();
   switch( CurrentSearch->State )
   {
   case SEARCH_STATE_ARTIST:
      // Selected an artist, get all albums
      if( info.Artist == m_AddAll )
      {
         printf( "Selected All Artists\n" );
      }
      else
      {
         SearchEvent* tmp = new SearchEvent( *CurrentSearch );
         SearchStack.push( tmp );
         CurrentSearch->Display = tr("Artist: ").append(info.Artist);
         selection_state_text.SetText( tr("Select by Album:") );
         CurrentSearch->State = SEARCH_STATE_ALBUM;
         CurrentSearch->prepare
         (
            "SELECT filename, artist, album from audio_tracks where"
            " artist=:ARTIST"
            " group by album"
            " order by year, album;"
         );
         CurrentSearch->bindValue( ":ARTIST", info.Artist );
         PerformSearch( CurrentSearch );
         CurrentSearch->prepare
         (
            "SELECT filename, artist, album from audio_tracks where"
            " artist=:ARTIST"
            "    and"
            " album_search regexp :EXPRESSION"
            " group by album"
            " order by year, album;"
         );
         CurrentSearch->bindValue( ":EXPRESSION", "[[:<:]]" );
         CurrentSearch->bindValue( ":ARTIST", info.Artist );
      }
      break;

   case SEARCH_STATE_ALBUM:
      if( info.Album == m_AddAll )
      {
         // Select everything by this artist
         printf( "Selecting everything for Artist %s\n", info.Artist.ascii() );
         MSqlQuery query(MSqlQuery::InitCon());
         query.prepare
         (
            "SELECT filename, artist, album, title from audio_tracks where"
            " artist=:ARTIST"
            " order by year, album, tracknum, title;"
         );
         query.bindValue( ":ARTIST", CurrentSearch->boundValue(":ARTIST") );
         query.exec();
         if( query.isActive() && query.size() > 0 )
         {
            while( query.next() )
            {
               info = new SelectionInfo();
               info.Path   = query.value(0).toString();
               info.Artist = query.value(1).toString();
               info.Album  = query.value(2).toString();
               info.Title  = query.value(3).toString();
               PlayListUI->Add( info.Title, info );
            }
            PlayListUI->Display();
         }
      }
      else
      {
         // Selected an album, get all tracks
         SearchEvent* tmp = new SearchEvent( *CurrentSearch );
         SearchStack.push( tmp );
         CurrentSearch->Display = tr("Album: ").append(info.Album);
         selection_state_text.SetText( tr("Select by Track:") );
         CurrentSearch->State = SEARCH_STATE_TRACK;
         CurrentSearch->prepare
         (
            "SELECT filename, artist, album, title from audio_tracks where"
            " artist=:ARTIST"
            "    and"
            " album=:ALBUM"
            " order by tracknum, title;"
         );
         CurrentSearch->bindValue( ":ARTIST", info.Artist );
         CurrentSearch->bindValue( ":ALBUM",  info.Album );
         PerformSearch( CurrentSearch );
         CurrentSearch->prepare
         (
            "SELECT filename, artist, album, title from audio_tracks where"
            " artist=:ARTIST"
            "    and"
            " album=:ALBUM"
            "    and"
            " title_search regexp :EXPRESSION"
            " order by tracknum, title;"
         );
         CurrentSearch->bindValue( ":ARTIST", info.Artist );
         CurrentSearch->bindValue( ":ALBUM",  info.Album );
         CurrentSearch->bindValue( ":EXPRESSION", "[[:<:]]" );
      }
      break;

   case SEARCH_STATE_TRACK:
      if( info.Title == m_AddAll )
      {
         printf( "Selected All Tracks\n" );
         // Skip the first item as it is m_AddAll
         for( i=1; i<SelectionListUI->Count(); i++ )
         {
            info = SelectionListUI->Get( i );
            PlayListUI->Add( info.Title, info );
         }
         PlayListUI->Display();
      }
      else
      {
         printf( "Selected Title %s\n", info.Title.ascii() );
         PlayListUI->Add( info.Title, info );
         PlayListUI->Display();
      }
      return;
   }
}

void PlaybackBoxMusic::PerformSearch( SearchEvent* search )
{
   SelectionInfo* info;

   search->exec();

   selection_string_text.SetText( CurrentSearch->Display );

   SelectionListUI->ResetList();
   switch( search->State )
   {
   case SEARCH_STATE_ALBUM:
   case SEARCH_STATE_TRACK:
      info = new SelectionInfo();
      info->Artist = m_AddAll;
      info->Album = m_AddAll;
      info->Title = m_AddAll;
      SelectionListUI->Add( m_AddAll, *info );
      break;
   }

   if( search->isActive() && search->size() > 0 )
   {
      while( search->next() )
      {
         info = new SelectionInfo();
         info->Path = search->value(0).toString();
         switch( search->State )
         {
         case SEARCH_STATE_ARTIST:
            info->Artist = search->value(1).toString();
            SelectionListUI->Add( info->Artist, *info );
            break;
         case SEARCH_STATE_ALBUM:
            info->Artist = search->value(1).toString();
            info->Album  = search->value(2).toString();
            SelectionListUI->Add( info->Album, *info );
            break;
         case SEARCH_STATE_TRACK:
            info->Artist = search->value(1).toString();
            info->Album  = search->value(2).toString();
            info->Title  = search->value(3).toString();
            SelectionListUI->Add( info->Title, *info );
            break;
         case SEARCH_STATE_DIRECTORY:
            break;
         case SEARCH_PLAYLIST:
            break;
         }
      }
   }

   SelectionListUI->Display();
}

bool PlaybackBoxMusic::BackOutSelection()
{
   bool rc =  false;

   if( SearchStack.count() > 0 )
   {
      delete CurrentSearch;
      CurrentSearch = SearchStack.pop();
      PerformSearch( CurrentSearch );
      selection_string_text.SetText( CurrentSearch->Display );
      rc = true;
   }

   return rc;
}

void PlaybackBoxMusic::showMenu()
{
   QButton* button;
   QLabel* splitter;

   if( playlist_popup )
   {
      return;
   }

   playlist_popup = new MythPopupBox(gContext->GetMainWindow(),"playlist_popup");

   if( menufilters )
   {
      QLabel *caption = playlist_popup->addLabel(tr("Change Filter"), MythPopupBox::Large);
      caption->setAlignment(Qt::AlignCenter);
   }

   button = playlist_popup->addButton(tr("Play"), this,SLOT(play()));
   playlist_popup->addButton(tr("Pause"), this,SLOT(pause()));
   playlist_popup->addButton(tr("Stop"), this,SLOT(stop()));
   playlist_popup->addButton(tr("Next"), this,SLOT(next()));
   playlist_popup->addButton(tr("Previous"), this,SLOT(previous()));
   splitter = playlist_popup->addLabel(" ", MythPopupBox::Small);
   playlist_popup->addButton(tr("Scan for Audio"), this,SLOT(scanForAudio()));
   playlist_popup->addButton(tr("Edit Playlist"), this,SLOT(EditPlaylist()));

   splitter->setLineWidth(2);
   splitter->setFrameShape(QFrame::HLine);
   splitter->setFrameShadow(QFrame::Sunken);
   splitter->setMaximumHeight((int) (5 * hmult));
   splitter->setMaximumHeight((int) (5 * hmult));

   playlist_popup->ShowPopup(this, SLOT(closePlaylistPopup()));

   button->setFocus();
}

void PlaybackBoxMusic::resetTimer()
{
   if( visual_mode_delay > 0 )
   {
      visual_mode_timer->changeInterval(visual_mode_delay * 1000);
   }
}

void PlaybackBoxMusic::play()
{
   closePlaylistPopup();
   m_AudioPlayer.Play();
}

void PlaybackBoxMusic::visEnable()
{
   if( !visualizer_status != 2 && isplaying )
   {
      setUpdatesEnabled(false);
      mainvisual->setGeometry(0, 0, screenwidth, screenheight);
      visualizer_status = 2;
   }
   else
   {
      bannerDisable();
   }
}

void PlaybackBoxMusic::bannerEnable(Metadata *mdata)
{
   if( visualizer_status != 2 )
   {
      return;
   }

   banner_timer->start(8000);
   mainvisual->addInformation("\"" + mdata->Title() + "\"\n" +
                              mdata->Artist() + " - " + mdata->Album());
}

void PlaybackBoxMusic::bannerToggle(Metadata *mdata)
{
   if( banner_timer->isActive() )
   {
      bannerDisable();
   }
   else
   {
      bannerEnable(mdata);
   }
}

void PlaybackBoxMusic::bannerDisable()
{
   banner_timer->stop();
   mainvisual->addInformation("");
}

void PlaybackBoxMusic::KeypressIdle()
{
   printf( "Keypress Idle\n" );
}

void PlaybackBoxMusic::setTrackOnLCD(Metadata *mdata)
{
   LCD *lcd = LCD::Get();
   if( !lcd )
   {
      return;
   }

   // Set the Artist and Tract on the LCD
   lcd->switchToMusic(mdata->Artist(),
                      mdata->Album(),
                      mdata->Title());
}

void PlaybackBoxMusic::pause(void)
{
   closePlaylistPopup();
   //m_AudioPlayer.Pause();
}

void PlaybackBoxMusic::stop(void)
{
   closePlaylistPopup();
   m_AudioPlayer.Stop();
}

void PlaybackBoxMusic::previous()
{
   closePlaylistPopup();
   m_AudioPlayer.Previous();
}

void PlaybackBoxMusic::next()
{
   closePlaylistPopup();
   m_AudioPlayer.Next();
}

void PlaybackBoxMusic::EditPlaylist()
{
   closePlaylistPopup();
   printf( "editPlaylist\n" );
}

void PlaybackBoxMusic::closeEvent(QCloseEvent *event)
{
   hide();
   event->accept();
}

void PlaybackBoxMusic::toggleFullBlankVisualizer()
{
   if( mainvisual->getCurrentVisual() == "Blank" &&
        visualizer_status == 2 )
   {
      //
      //  If we are already full screen and
      //  blank, go back to regular dialog
      //

      //if( visual_blackhole )
      //{
      //   mainvisual->setGeometry(visual_blackhole->getScreenArea());
      //}
      //else
      //{
         mainvisual->setGeometry(screenwidth + 10, screenheight + 10,
                                 160, 160);
      //}
      mainvisual->setVisual(visual_mode);
      bannerDisable();
      visualizer_status = 1;
      if( visual_mode_delay > 0 )
      {
         visual_mode_timer->start(visual_mode_delay * 1000);
      }
      current_visualization_text.SetText(mainvisual->getCurrentVisualDesc());
      setUpdatesEnabled(true);
   }
   else
   {
      //
      //  Otherwise, go full screen blank
      //

      mainvisual->setVisual("Blank");
      mainvisual->setGeometry(0, 0, screenwidth, screenheight);
      visualizer_status = 2;
      visual_mode_timer->stop();
      setUpdatesEnabled(false);
   }
}

void PlaybackBoxMusic::end()
{
   if( class LCD *lcd = LCD::Get() )
   {
      lcd->switchToTime ();
   }
}

void PlaybackBoxMusic::wireUpTheme()
{
   PlayListUI = new AudioUIList( *this, "playlist", PlaybackItemList );
   if( !PlayListUI )
   {
      cerr << "playbackbox.o: Could not find playlist in your theme" << endl;
      exit(0);
   }

   PlayListUI->ResetList();
   PlayListUI->SetActive( true );

   playlist_name_text.Load( this, "playlist_name" );
   playlist_state_text.Load( this, "playlist_state" );

   playlist_name_text.SetText(tr("Default"));
   playlist_state_text.SetText(tr("Idle"));

   SelectionListUI = new AudioUIList( *this, "selectionlist", SelectionItemList );
   if( !SelectionListUI )
   {
      cerr << "playbackbox.o: Could not find selectionlist in your theme" << endl;
      exit(0);
   }
   SelectionListUI->SetActive( true );

   selection_state_text.Load( this, "selection_state" );
   selection_string_text.Load( this, "selection_string" );

   selection_state_text.SetText( tr("Select by Artist:") );
   selection_string_text.SetText( tr("Selection: ") );

   InfoArtist.Load( this, "info_artist" );
   InfoAlbum.Load( this, "info_album" );
   InfoTitle.Load( this, "info_title" );

   StatusScan.Load( this, "scan_status" );
   StatusPlay.Load( this, "play_status" );
   StatusPlaybackMode.Load( this, "playback_mode" );
}

void PlaybackBoxMusic::scanForAudio()
{
   closePlaylistPopup();
   m_FileScanner->Start();
}

void PlaybackBoxMusic::closePlaylistPopup()
{
   if( !playlist_popup )
   {
      return;
   }

   playlist_popup->hide();
   delete playlist_popup;
   playlist_popup = NULL;
}

//=============================================================================
//
//=============================================================================

AudioUIList::AudioUIList( MythThemedDialog& parent, const QString& obj, QValueVector<SelectionInfo>& list )
:
   ItemList(list)
{
   UIList = (UIListType*)parent.getUIObject(obj);
   ResetList();
   UIList->SetActive( false );
   ItemList = list;
}

AudioUIList::~AudioUIList()
{
}

void AudioUIList::ResetList()
{
   First = 0;
   Current = 0;

   UIList->ResetList();
   DisplayList.clear();
   ItemList.clear();
}

void AudioUIList::Refresh()
{
   UIList->refresh();
}

int AudioUIList::GetItems()
{
   return UIList->GetItems();
}

void AudioUIList::SetActive( bool active )
{
   Active = active;
   UIList->SetActive( active );
   Refresh();
}

bool AudioUIList::IsActive()
{
   return Active;
}

void AudioUIList::SetItemCurrent( int item )
{
   UIList->SetItemCurrent( item );
}

int AudioUIList::GetCurrentItem()
{
   return UIList->GetCurrentItem();
}

void AudioUIList::LineUp()
{
   if( Current > 0 )
   {
      Current--;
   }

   Display();
}

void AudioUIList::LineDown()
{
   if( Current < (int)DisplayList.count() )
   {
      Current++;
   }

   Display();
}

void AudioUIList::PageDown()
{
   Current += UIList->GetItems()-1;
   if( Current >= (int)DisplayList.count() )
   {
      Current = DisplayList.count() - 1;
   }
   Display();
}

void AudioUIList::PageUp()
{
   Current -= UIList->GetItems()-1;
   if( Current < 0 )
   {
      Current = 0;
   }
   Display();
}

void AudioUIList::Display()
{
   int count;
   int row;
   int selectedRow;
   QString info;
   bool ok;
   int center = UIList->GetItems()/2;

   if( Current >= (int)DisplayList.count() && DisplayList.count() > 0 )
   {
      Current = DisplayList.count()-1;
   }
   else if( Current < 0 )
   {
      Current = 0;
   }

   if( (int)DisplayList.count() <= UIList->GetItems() )
   {
      // Entire display list fits in the visible window
      First = 0;
   }
   else
   {
      if( Current < center )
      {
         // Close to top of list
         First = 0;
      }
      else if( Current > (int)DisplayList.count() - center - 1 )
      {
         // Close to bottom of list
         First = DisplayList.count() - UIList->GetItems();
      }
      else
      {
         // In center of list
         First = Current - center;
      }
   }

   selectedRow = Current - First;

   UIList->ResetList();

   count = DisplayList.count();
   for( row=0; row<UIList->GetItems(); row++ )
   {
      if( First+row >= count )
      {
         break;
      }
      info = DisplayList.at( First+row, &ok );

      if( ok == 0 || info.isNull() )
      {
         break;
      }

      UIList->SetItemText(row, info);
   }

   UIList->SetItemCurrent( selectedRow );
   UIList->refresh();
}

void AudioUIList::Add( const QString& display, const SelectionInfo& item )
{
   DisplayList.append( display );
   ItemList.append( item );
}

SelectionInfo AudioUIList::GetCurrent()
{
   return ItemList.at( Current );
}

SelectionInfo AudioUIList::Get( int index )
{
   return ItemList.at( index );
}

void AudioUIList::EnableForcedFont( int row, QString func )
{
   UIList->EnableForcedFont( row, func );
}

